package jnpf.base.service.impl;


import jnpf.base.DbTableModel;
import jnpf.database.enums.DbModelEnum;
import jnpf.database.enums.DbSttEnum;
import jnpf.database.model.dto.DbListVO;
import jnpf.database.source.DbBase;
import jnpf.database.util.DbUtil;
import jnpf.exception.DataException;
import jnpf.base.ActionResult;
import jnpf.base.service.DbTableService;
import jnpf.base.service.DblinkService;
import jnpf.config.ConfigValueUtil;
import jnpf.base.entity.DbLinkEntity;
import jnpf.database.model.DbTableDataForm;
import jnpf.database.model.DbTableFieldModel;
import jnpf.database.model.dto.DbTableDTO;
import jnpf.util.*;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据管理
 *
 * @author JNPF开发平台组
 * @version V3.1.0
 * @copyright 引迈信息技术有限公司
 * @date 2019年9月27日 上午9:18
 */
@Slf4j
@Service
public class DbTableServiceImpl implements DbTableService {

    @Autowired
    private DblinkService dblinkService;
    @Autowired
    private DataSourceUtil dataSourceUtils;
    @Autowired
    private UserProvider userProvider;
    @Autowired
    private ConfigValueUtil configValueUtil;

    @Override
    public List<DbTableModel> getList(String dbId) throws DataException {
        return getListCommon(dbId, "",DbModelEnum.TABLE_MODEL).getDbTableList();
    }

    @Override
    public List<DbTableFieldModel> getFieldList(String dbId, String table) throws DataException {
       return getListCommon(dbId,table,DbModelEnum.FIELD_MODEL).getDbTableFieldList();
    }

    private  DbListVO getListCommon(String dbId, String table, DbModelEnum dbModelEnum) throws DataException{
        Map map = getConnCommon(dbId);
        try {
            @Cleanup Connection conn = (Connection) map.get("conn");
            DbBase dbBase = DbUtil.getDbByContainsConn(conn);
            if (conn != null) {
                //获取查询sql语句
                String sql = dbBase.getSqlByStructure
                        (dbModelEnum.getModelSql(dbBase),conn,table,(String) map.get(DbSttEnum.TABLE_SPACE.name()));
                //根据sql语句获取List
                return  dbModelEnum.getModelList(conn,sql,dbBase);
            }
        }catch (Exception e){
            e.getMessage();
        }
        return new DbListVO();
    }

    /**
     * 获取连接实例
     * @param dbId
     * @return
     */
    private Map<String,Object> getConnCommon(String dbId) throws DataException {
        String tableSpace;
        Connection conn = null;
        DbLinkEntity link = dblinkService.getInfo(dbId);
        //多租户是否开启
        String tenSource =
                Boolean.parseBoolean(configValueUtil.getMultiTenancy()) ?
                        userProvider.get().getTenantDbConnectionString() : "";
        if (link != null) {
            //判断字典数据类型编码是否错误，大小写不敏感
            DbBase db = DbUtil.getDbByEquals(link.getDbType());
            if(db==null){
                throw DataException.getEnCodeException();
            }
            //查询其他数据库信息
            try {
                conn = JdbcUtil.getConn(db, link.getUserName(),
                        link.getPassword(), link.getHost(), link.getPort(), link.getServiceName());
            } catch (Exception e) {
                throw new DataException(e.getMessage());
            }
            tableSpace = link.getTableSpace();
        } else {
            //默认数据库查询，从配置获取数据源信息
            tenSource = StringUtil.isEmpty(tenSource) ? dataSourceUtils.getDbName() : tenSource;
            String url = dataSourceUtils.getUrl().replace(DbSttEnum.DB_NAME.getTarget(), tenSource);
            conn = JdbcUtil.getConn(dataSourceUtils.getUserName(), dataSourceUtils.getPassword(), url);
            tableSpace = dataSourceUtils.getTableSpace();
        }
        HashMap map = new HashMap(2);
        map.put("conn",conn);
        map.put(DbSttEnum.TABLE_SPACE.name(),tableSpace);
        return map;
    }


    @Override
    public List<Map<String, Object>> getData(DbTableDataForm dbTableDataForm, String dbId, String table) {
        List<Map<String, Object>> list = null;
        try {
            @Cleanup Connection conn = (Connection)getConnCommon(dbId).get("conn");
            DbBase dbBase = DbUtil.getDbByContainsConn(conn);
            if (conn != null) {
                StringBuffer sql = new StringBuffer();
                sql.append(dbBase.getDataSql().replace(DbSttEnum.TABLE.getTarget(),table));
                //模糊查询
                if (!StringUtil.isEmpty(dbTableDataForm.getKeyword()) && !StringUtil.isEmpty(dbTableDataForm.getField())) {
                    sql.append(" where " + dbTableDataForm.getField() + " like '%" + dbTableDataForm.getKeyword() + "%'");
                }
                ResultSet query = JdbcUtil.query(conn, sql.toString());
                list = JdbcUtil.convertListString(query);
            }
        }catch (Exception e){
            e.getMessage();
        }
        return dbTableDataForm.setData(PageUtil.getListPage((int) dbTableDataForm.getCurrentPage(), (int) dbTableDataForm.getPageSize(), list), list.size());
    }

    @Override
    public boolean isExistByFullName(String dbId, String table, String oldTable) {
        List<DbTableModel> data = null;
        try {
            data = this.getList(dbId).stream().filter(m -> m.getTable().equals(table)).collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!StringUtil.isEmpty(oldTable)) {
            data = data.stream().filter(m -> !m.getTable().equals(oldTable)).collect(Collectors.toList());
        }
        return data.size() > 0;
    }

    @Override
    public String getDbTime(String dbId) throws DataException {
        DbLinkEntity link = dblinkService.getInfo(dbId);
        String time = "";
        try {
            @Cleanup Connection conn = null;
            if (link != null) {
                conn = JdbcUtil.getConn(link.getDbType().toLowerCase(), link.getUserName(), link.getPassword(), link.getHost(), link.getPort(), link.getServiceName());
                if (conn != null) {
                    DbBase db = DbUtil.getDbByEquals(link.getDbType().toLowerCase());
                    time = db.getDbTime(conn);
                }
            }
        } catch (Exception e) {
            throw new DataException(e.getMessage());
        }
        return time;
    }

    @Override
    public int executeSql(String dbId, String strSql) throws DataException {
        DbLinkEntity link = dblinkService.getInfo(dbId);
        int result = 0;
        try {
            @Cleanup Connection conn=null;
            if (link != null) {
                conn = JdbcUtil.getConn(link.getDbType().toLowerCase(), link.getUserName(), link.getPassword(), link.getHost(), link.getPort(), link.getServiceName());
                if (conn != null) {
                    result = JdbcUtil.custom(conn, strSql);
                }
            }
        } catch (Exception e) {
            throw new DataException(e.getMessage());
        }
        return result;
    }




    @Override
    public void delete(String dbId, String table) {
        try {
            @Cleanup Connection conn = (Connection)getConnCommon(dbId).get("conn");
            DbBase dbBase = DbUtil.getDbByContainsConn(conn);
            if (conn != null) {
                String sql = dbBase.getDeleteSql().replace(DbSttEnum.TABLE.getTarget(),table);
                JdbcUtil.custom(conn, sql);
            }
        }catch (Exception e){
            e.getMessage();
        }
    }

    @Override
    public ActionResult create(String dbId, DbTableModel dbTableModel, List<DbTableFieldModel> tableFieldList) throws DataException {
        Map map = getConnCommon(dbId);
        Connection conn = (Connection)map.get("conn");
        if(conn != null){
            DbBase dbBase = DbUtil.getDbByContainsConn(conn);
            dbBase.createTable(
                    new DbTableDTO(
                            conn,
                            dbTableModel,
                            tableFieldList,
                            (String)map.get(DbSttEnum.TABLE_SPACE.name())
                    )
            );
            return ActionResult.success("新建成功");
        }else {
            return ActionResult.fail("连接失败");
        }
    }

    @Override
    public void update(String dbId, DbTableModel dbTableModel, List<DbTableFieldModel> tableFieldList) throws DataException {
        Map map = getConnCommon(dbId);
        Connection conn = (Connection)map.get("conn");
        String tableSpace = (String)map.get(DbSttEnum.TABLE_SPACE.name());
        if(conn != null) {
            DbBase dbBase = DbUtil.getDbByContainsConn(conn);
            dbBase.updateTable(
                    new DbTableDTO(
                            conn,
                            dbTableModel,
                            tableFieldList,
                            tableSpace)
            );
        }
    }

}
